package com.xwaf.platform.system.api.entity.pay.wx;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 
 * <p>
 * 微信签名相关
 * <p>
 * 
 * @author 李聪 <br>
 * @email xwaf_love@yeah.net <br>
 * @since JDK 1.8<br>
 * @date 2019年12月30日 上午8:51:53 <br>
 * @see 无<br>
 *      Copyright (c) 2019, xwaf_love@yeah.net All Rights Reserved.<br>
 */
public class WeiXinSignature {

	private static final Logger logger = LoggerFactory.getLogger(WeiXinSignature.class);

	/**
	 * <p>
	 * 签名算法,对象
	 * <p>
	 * 
	 * @author 李聪 <br>
	 * @email xwaf_love@yeah.net <br>
	 * @since JDK 1.8<br>
	 * @date 2019年12月30日 上午8:52:00 <br>
	 * @see 无<br>
	 * @param o
	 *            要参与签名的数据对象
	 * @param apiKey
	 * @return 签名
	 * @throws IllegalAccessException
	 * @demo <br>
	 */
	@SuppressWarnings("rawtypes")
	public static String getSign(Object o, String apiKey) throws IllegalAccessException {
		ArrayList<String> list = Lists.newArrayList();
		Class cls = o.getClass();
		Field[] fields = cls.getDeclaredFields();
		for (Field f : fields) {
			f.setAccessible(true);
			if (f.get(o) != null && f.get(o) != "") {
				list.add(f.getName() + "=" + f.get(o) + "&");
			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		String result = sb.toString();
		result += "key=" + apiKey; //
		result = WeiXinMD5.MD5Encode(result, null).toUpperCase();
		return result;
	}

	/**
	 * 
	 * <p>
	 * 签名算法
	 * <p>
	 * 
	 * @author 李聪 <br>
	 * @email xwaf_love@yeah.net <br>
	 * @since JDK 1.8<br>
	 * @date 2019年12月30日 上午8:52:20 <br>
	 * @see 无<br>
	 * @param map
	 * @param apiKey
	 * @return
	 * @demo <br>
	 */
	public static String getSign(Map<String, Object> map, String apiKey) {
		ArrayList<String> list = new ArrayList<String>();
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			if (entry.getValue() != "") {
				list.add(entry.getKey() + "=" + entry.getValue() + "&");
			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		String result = sb.toString();
		result += "key=" + apiKey;
		result = WeiXinMD5.MD5Encode(result, "UTF-8").toUpperCase();
		return result;
	}

	/**
	 * 
	 * <p>
	 * 检验API返回的数据里面的签名是否合法，避免数据在传输的过程中被第三方篡改
	 * <p>
	 * 
	 * @author 李聪 <br>
	 * @email xwaf_love@yeah.net <br>
	 * @since JDK 1.8<br>
	 * @date 2019年12月30日 上午8:52:27 <br>
	 * @see 无<br>
	 * @param map
	 *            API返回的XML数据字符串对应 map
	 * @param apiKey
	 * @return API签名是否合法
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws IllegalAccessException
	 * @demo <br>
	 */
	public static boolean checkIsSignValidFromMap(Map<String, String> map, String apiKey)
			throws ParserConfigurationException, IOException, SAXException, IllegalAccessException {
		logger.info(map.toString());
		String signFromAPIResponse = map.get("sign").toString();
		if (StringUtils.isBlank(signFromAPIResponse)) {
			return false;
		}
		map.put("sign", "");
		String signForAPIResponse = WeiXinSignature.getSign(map, apiKey);
		if (StringUtils.equals(signForAPIResponse, signFromAPIResponse)) {
			return false;
		}
		logger.info("恭喜，API返回的数据签名验证通过!!!");
		return true;
	}

	/**
	 * <p>
	 * 构造客户端调起微信支付的参数签名数据
	 * <p>
	 * 
	 * @author 李聪 <br>
	 * @email xwaf_love@yeah.net <br>
	 * @since JDK 1.8<br>
	 * @date 2019年12月30日 上午8:52:49 <br>
	 * @see 无<br>
	 * @param appid
	 * @param noncestr
	 * @param partnerid
	 * @param prepayid
	 * @param timestamp
	 * @param apiKey
	 * @return
	 * @throws IllegalAccessException
	 * @demo <br>
	 */
	public static String genWechatPaySign(String appid, String noncestr, String partnerid, String prepayid,
			String timestamp, String apiKey) throws IllegalAccessException {
		Map<String, Object> signSrcMap = Maps.newHashMap();
		signSrcMap.put("appid", appid);
		signSrcMap.put("noncestr", noncestr);
		signSrcMap.put("package", "Sign=WXPay");
		signSrcMap.put("partnerid", partnerid);
		signSrcMap.put("prepayid", prepayid);
		signSrcMap.put("timestamp", timestamp);
		return getSign(signSrcMap, apiKey);
	}
}
